'''
Created on 28/09/2009

@author: b1u3fox
'''
class Simbolo(object):
    def __init__(self, nombre):
        self.nombre = nombre
        self.valor = None
        
    def __repr__(self):
        return '<%s, %s>' % (self.nombre, str(self.valor))

class TablaSimbolos(object):
    def __init__(self):
        self.simbolos = {}
        
    def obtener_simbolo(self, nombre):
        if self.simbolos.has_key(nombre):
            return self.simbolos[nombre]
        else:
            simbolo = Simbolo(nombre)
            self.simbolos[nombre] = simbolo
            return simbolo

class Multilinea(object):
    
    def __init__(self):
        self.indice_caracter = 0
        self.cadena = ''
        self.fda = True
        
    def avanzar(self):
        if self.indice_caracter < len(self.cadena) - 1:
            self.indice_caracter += 1
        else:
            self.fda = True
        
    def caracter_actual(self):
        return self.cadena[self.indice_caracter]
    
    def iniciar(self, cadena=None):
        if cadena:
            self.cadena = cadena
        self.indice_caracter = 0
        self.fda = len(self.cadena) == 0
        
        
class Token(object):
    FDA = 'FDA'
    ERROR = 'ERROR'
    
    def __init__(self, tipo, valor, inicio=0, fin=0):
        self.tipo = tipo
        self.valor = valor
        self.inicio = 0
        self.fin = 0
        
    def __repr__(self):
        return '(%s, %s)' % (self.tipo, self.valor) 
    

class Analex(object):
    
    def __init__(self, tabla_simbolos=None):
        self.tabla_simbolos = tabla_simbolos or TablaSimbolos() 
        self.multilinea = Multilinea()
        self.acumulador = ''
        self.ultimo_token = None
        self.nro_linea = 1
        self.nro_caracter = 0
        
    def _analizar(self):
        pass
    
    def preanalisis(self):
        if self.ultimo_token == None:
            self.ultimo_token = self._analizar()
        return self.ultimo_token
    
    def avanzar(self):
        self.ultimo_token = self._analizar()
    
    def iniciar(self, cadena=None):
        self.multilinea.iniciar(cadena)
        self.acumulador = ''
        self.ultimo_token = None
        self.nro_linea = 1
        self.nro_caracter = 0
     
        
class ErrorParseo(Exception):
    def __init__(self, nro_linea, nro_caracter, tipos_token_esperados=[]):
        self.nro_linea = nro_linea
        self.nro_caracter = nro_caracter
        self.tipos_token_esperados = tipos_token_esperados
        msg = 'Error en la linea %d, caracter %d. Se esperaba %s.'
        msg = msg % (nro_linea, nro_caracter, ' o '.join(tipos_token_esperados)) 
        Exception.__init__(self, msg)

        
class Parser(object):
    def __init__(self, tabla_simbolos=None):
        self.tabla_simbolos = tabla_simbolos or TablaSimbolos()
        self.analex = None
        self.error_found = False
        
    def _arrojar_error(self, tipos_tokens_esperados):
        raise ErrorParseo(self.analex.nro_linea, 
                          self.analex.nro_caracter, 
                          tipos_tokens_esperados)
    
    def _emparejar(self, token, tipo_token):
        if token.tipo == tipo_token:
            self.analex.avanzar()
        else:
            # TODO: Arrojar error desplegable desde la interfaz
            self.error_found = True
            self._arrojar_error([tipo_token])
        
    def parse(self, cadena):
        pass
